﻿package api;

import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLVariables;

import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.events.Event;

class DataProvider {
    public static inline var API_SERVER_URL: String = "http://api.vkontakte.ru/api.php";
    public static inline var GET_VARIABLE: String    = "getVariable";
    public static inline var PUT_VARIABLE: String    = "putVariable";
    public static inline var GET_VARIABLES: String   = "getVariables";
    public static inline var GET_MESSAGES: String    = "getMessages";
    public static inline var SEND_MESSAGE: String    = "sendMessage";
    public static inline var GET_HIGH_SCORES: String = "getHighScores";
    public static inline var SEND_USER_SCORE: String = "sendUserScore";
    public static inline var GET_USER_INFO: String   = "getUserInfo";
    public static inline var GET_SERVER_TIME: String = "getServerTime";
    
    private var apiId: Int;
    private var apiSecret: String;
    private var viewerId: Int;
    private var testMode: Bool;
    private var requestParams: Array<Dynamic>;
    
    public function new(apiId: Int, apiSecret: String, viewerId: Int, testMode: Bool = false) {
		this.apiId = apiId;
		this.apiSecret = apiSecret;
		this.viewerId = viewerId;
		this.testMode  = testMode;
    }
    
	function Utf8Encode(string: String) {
		var utftext = "";
		var n = 0;
		while (n < string.length) {
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			n++;
		}
 
		return utftext;
	}

	
    public function request(method: String, params: {}, onComplete: Xml -> Void, onError: String -> Void) {
		var requestParams = new URLVariables();
		if (params != null) {
			for (field in Reflect.fields(params)) {
				// if param is null skip it
				if (Reflect.field(params, field) != null) {
					Reflect.setField(requestParams, field, Reflect.field(params, field));
				}
			}
		}
		Reflect.setField(requestParams, "method", method);
		Reflect.setField(requestParams, "api_id", apiId);
		Reflect.setField(requestParams, "format", "XML");
		Reflect.setField(requestParams, "v", "2.0");
		if (testMode) {
			Reflect.setField(requestParams, "test_mode", "1");
		}
		Reflect.setField(requestParams, "sig", generateSignature(requestParams));
		
		var request = new URLRequest(API_SERVER_URL);
		request.method = URLRequestMethod.POST;
		request.data = requestParams;
		//trace("Request data: " + request.data);
	  
		var loader = new URLLoader();
		loader.dataFormat = URLLoaderDataFormat.TEXT;
		if (onError != null) {
			loader.addEventListener(IOErrorEvent.IO_ERROR, function(e: Dynamic) {
				onError("Connection error occured: " + e);
			});
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e: Dynamic) {
				onError("Security error occured: " + e);
			});
		}
	  
		if (onComplete != null) {
			loader.addEventListener(Event.COMPLETE, function(e:Event){
				var data = loader.data;
				onComplete(Xml.parse("" + data));
			});
		}
		try {
			loader.load(request);
		} catch (e: Dynamic) {
			if (onError != null) {
				onError("" + e);
			}
		}
    }

    private function generateSignature(requestParams: URLVariables): String {
		var signature = "";
		var sortedArray = new Array<String>();
		for (field in Reflect.fields(requestParams)) {
			sortedArray.push(field + "=" + Reflect.field(requestParams, field));
		}
		sortedArray.sort(this.compare);
		
		// Note: make sure that the signature parameter is not already included in
		//       request_params array.
		for (key in sortedArray) {
			signature += Utf8Encode(key);
		}
		signature = viewerId + signature + apiSecret;
		//trace("Signature: " + signature);
		return haxe.Md5.encode(signature);
    }
	
	private function compare(s1: String, s2: String): Int {
		var i = 0;
		
		while (i < s1.length && i < s2.length) {
			if (s1.charAt(i) > s2.charAt(i)) {
				return 1;
			} else if (s1.charAt(i) < s2.charAt(i)) {
				return -1;
			} else {
				i++;
			}
		}
		
		if (i == s1.length) {
			if (i == s2.length) {
				return 0;
			} else {
				return -1;
			}
		} else {
			return 1;
		}
	}
 }
